home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: Various
/
DevDisk 65 (1989)(DevWare PD).zip
/
DevDisk 65 (1989)(DevWare PD).adf
/
scroll
/
SD.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-08-07
|
19KB
|
664 lines
/*------------------------------------------------------------------------*/
/* Double-Buffered Infinite BitMap Scroll Demo */
/* */
/* by Mark E. Whitehead 23 SEP 89 */
/* */
/* THIS IS FREELY DISTRIBUTABLE PUBLIC DOMAIN SOFTWARE! */
/* No charge should be made except for a copying fee. */
/* If you find a use for this program please give me some */
/* credit; otherwise next time all the variable names will */
/* read something like 'xAcdW3q2'. Doomo Arigatoo! */
/* */
/* */
/* This program demonstrates a double-buffered 'infinite' smooth */
/* scrolling display using Standard Amiga graphics routines. It also */
/* features Simple Sprite animation. The program creates a randomly */
/* generated terrain which scrolls from top to bottom. The user controls */
/* a Spaceship with the joystick while alien 'flying saucers' zig-zag down*/
/* the screen. The joystick button also launches a missle. NO collision */
/* detection is performed - that is beyond the scope of this demo. Other */
/* than that almost everything is here to get you started on your first */
/* Space Shoot-em-up game! But first, a word about what we've got to */
/* work with... */
/* The Amiga has built-in hardware scrolling capability but is is not*/
/* practical for large bitmaps since the memory requirements are very */
/* intensive. A better method is to scroll the screen using the BLITTER */
/* and to "update" the graphics in the opposite direction with new data. */
/* Fortunately, we don't have to mess around with the blitter chip */
/* directly since SCROLLRASTER() has been provided in ROM. (Thanks!) */
/* When the screen is scrolled without double-buffering there tends */
/* to be some separation of the bit planes causing psychodelic colors to */
/* leak through, as well as a kind of ~~~wave~~~. Double-buffering stops */
/* this by making sure that all the bit planes have been moved into place */
/* before being displayed. So there ya go.. */
/* In pictorial form here is how the program solves the problem: */
/* */
/* +-----+-----+-----+-----+ --------------------- */
/* | a | b | c | d | new data buffer | */
/* |-----+-----+-----+-----| ------------------ | */
/* | e | f | g | h | | This is one of the */
/* |-----+-----+-----+-----| | two BitMaps which */
/* | | | | | | are alternately */
/* | | ViewPort attached to the */
/* ~ ~ shows this RastPort */
/* ~ ~ much of Raster | */
/* |-----------------------| | | */
/* | | | | | | | */
/* +-----------------------+ --------------------- */
/* */
/* What area of the BitMap (Raster) is defined by the Position of */
/* the ViewPort. In this case it is adjusted down the height of the */
/* terrain blocks. The letters 'a','b','c' etc. above are block */
/* shapes which in this program are randomly laid out but can be fed */
/* in from a pre-defined array! */
/* */
/*------------------------------------------------------------------------*/
#include <functions.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <graphics/sprite.h>
#include <stdio.h>
#include "images.c" /* The user defines block shapes in this file */
/* Note ye well that this data is not copied */
/* into CHIP memory and thus must be LINKED */
/* apropriately such as 'ln +cd scroll' (MANX)*/
#include "sprimages.c" /* The user defines sprites in this file */
#define ever (;;)
#define REV 0L
#define abs(x) ( ((x) < 0) ? -(x) : (x) )
#define GROUND 0 /* These are the block shapes which */
#define VOLCANO 1 /* define the terrain piecemeal */
#define PLANT 2
#define NSPRITES 7
#define SPRSIZE (2L*32L+4L) /* Space for LARGEST Sprite */
#define SHIPL 0
#define SHIPR 1
#define ALIEN0 2
#define ALIEN1 3
#define ALIEN2 4
#define ALIEN3 5
#define MISSILE 6
#define TOP 0
#define BOTTOM 200
#define LEFT 10
#define RIGHT 290
UWORD colortable[] = {
0x0000, 0x0ea6, 0x0e93, 0x0e81, /* Background */
0x0d70, 0x03a0, 0x0a20, 0x0380, /* Background */
0x0000, 0x0000, 0x0000, 0x0000, /* Unused */
0x0000, 0x0000, 0x0000, 0x0000, /* Unused */
0x0000, 0x0000, 0x0ccc, 0x0f00, /* Missile */
0x0000, 0x0000, 0x088f, 0x052f, /* Ship l & r */
0x0000, 0x0000, 0x0ccc, 0x0888, /* Aliens */
0x0000, 0x0000, 0x0ccc, 0x0888, /* Aliens */
};
#define BLK_W 32 /* Each terrain block is 32 pix wide */
#define BLK_H 20 /* Each terrain block is 20 pix high */
#define BLK_D 3 /* Each terrain block is 3 planes deep */
#define N_HBLK 10 /* There are 10 blocks across the scrn */
#define N_VBLK 11 /* There are 10 blocks down the scrn */
/* plus one buffer row */
#define DEPTH 3L /* 'L' added so I don't */
#define WIDTH 320L /* have to cast later..*/
#define HEIGHT 200L /* Height of Viewport */
#define RHEIGHT (HEIGHT + (long) BLK_H) /* Height of Raster */
struct Screen *scrn;
struct Window *win;
struct ViewPort *vp;
struct RastPort *rp;
struct BitMap *bitmap_ptrs[2] = { NULL, NULL }; /* U need this! */
WORD toggle_page = 0;
struct Image block = { 0, 0, BLK_W, BLK_H, BLK_D, NULL, 0x7, 0x0, NULL};
struct IntuiMessage *msg = NULL;
void *GfxBase, *IntuitionBase;
struct NewWindow windef = {
0, 0, WIDTH, 10,
1, 0,
CLOSEWINDOW | VANILLAKEY,
WINDOWCLOSE | BORDERLESS | ACTIVATE,
NULL, NULL, NULL, NULL, NULL,
0, 0, 0, 0,
CUSTOMSCREEN
};
struct NewScreen scrndef = {
0, 0, WIDTH, HEIGHT, DEPTH,
0, 1,
SPRITES,
CUSTOMSCREEN | CUSTOMBITMAP,
NULL, NULL, NULL, NULL
};
short rowdata[N_HBLK]; /* Store terrain data here for reference */
UWORD *sprbuffer = NULL; /* Pointer to CHIP memory buffer we make */
struct SimpleSprite shiplspr, shiprspr, mslspr, alienspr[4];
short dx[4] = { 2, -1, -2, 1 }, cx[4] = { 40, 50, 20, 100 },
x[4] = { 100, 40, 200, 280 }, y[4] = { 170, 10, 160, 80 },
sx = 140, sy = 160, mx = 0, my = 200;
short fire_cmd = FALSE, misl_on = FALSE;
/*--------------------- M A I N R O U T I N E ------------------------*/
main()
{
short i,
count = 1, /* Initialize count to 1 for first time */
pause = TRUE, /* Let the user read the options first... */
tracer = TRUE, /* Toggle Page number text on screen */
newrow = FALSE; /* This flag indicates a new row is needed */
UBYTE code;
ULONG class;
openstuff(); /* Open intuition, graphics, screen, window */
setupsprites();
/* For first pass plaster GROUND terrain across page 0 */
paint_pf();
pageflip();
/* For first pass plaster GROUND terrain across page 1 */
paint_pf();
ScrollRaster( rp, 0L, -1L, 0L, 0L, 320L, 219L);
pageflip();
/* NOTE: now we have two bitmaps with the same picture; with one */
/* bitmap exactly ONE row lower than the other. When we go to */
/* scrolling them we will move each exactly TWO rows! This will */
/* have the effect of the screen moving only one line at a time */
/* when we toggle back and forth. Think about it for awhile... */
for ever {
if (msg = (struct IntuiMessage *) GetMsg(win->UserPort) ) {
class = msg->Class;
code = msg->Code;
ReplyMsg(msg);
switch (class) {
case CLOSEWINDOW: closestuff();
return;
case VANILLAKEY: switch (code) {
case 'Q': case 'q':
closestuff();
return;
case 'T': case 't':
tracer = !tracer;
break;
case ' ': pause = !pause;
break;
}
}
}
if (!pause) {
ScrollRaster( rp, 0L, -2L, 0L, 0L, 320L, 219L);
if (newrow) {
draw_new_row();
newrow = FALSE;
}
if (++count >= BLK_H) {
/* This data can come from a pre-defined */
/* array just as easily! */
for (i=0; i<N_HBLK; i++)
rowdata[i] = RangeRand(5L);
draw_new_row();
newrow = TRUE;
count = 0;
}
for (i=0; i<4; i++) move_aliens( i);
move_ship();
move_missle();
if (tracer)
switch (toggle_page) {
case 0: jamit( 10, 218, 1, "Page 0"); break;
case 1: jamit( 260, 218, 1, "Page 1"); break;
}
pageflip(); /* Now - FLIP TO THE HIDDEN PAGE! */
}
}
}
/*------------------------------------------------------------------------*/
/* Move missle on screen */
move_missle()
{
if (misl_on) { /* If missle on screen... */
if ( (my -= 6) <= TOP) {
misl_on = FALSE; /* If at top move offscreen */
MoveSprite( vp, &mslspr, (long) 0, (long) 200);
} else /* Else keep going up */
MoveSprite( vp, &mslspr, (long) mx, (long) my);
} else { /* NOT on screen */
if (fire_cmd) {
misl_on = TRUE; /* Put onscreen if commanded */
mx = sx + 14;
my = sy - 16;
MoveSprite( vp, &mslspr, (long) mx, (long) my);
}
}
}
/*------------------------------------------------------------------------*/
/* Move Ship under joystick control */
move_ship()
{
short dx = 0, dy = 0;
joystick( &dx, &dy, &fire_cmd);
sx += dx<<1; sy += dy<<1;
if (sx < 10) sx = 10; else if (sx > 280) sx = 280;
if (sy > 160) sy = 160; else if (sy < 10) sy = 10;
MoveSprite( vp, &shiplspr, (long) sx, (long) sy);
MoveSprite( vp, &shiprspr, (long) sx+16, (long) sy);
}
/*------------------------------------------------------------------------*/
/* Move Aliens in a zig-zag diving pattern */
move_aliens(i)
short i;
{
if (--(cx[i]) < 0) {
cx[i] = 50 + RangeRand(100L); /* New charge duration */
dx[i] = -dx[i]; /* Go the other way... */
}
if ( cx[i] < 15)
y[i] += 3;
else
if ( cx[i] < 40)
y[i] += 2;
else
++(y[i]);
if ( y[i] > BOTTOM) {
y[i] = TOP; /* Re-position at top */
x[i] = 50 + RangeRand(200L); /* New starting x pos */
}
x[i] += dx[i];
if ( x[i] < LEFT || x[i] > RIGHT) dx[i] = -dx[i];
MoveSprite( vp, &alienspr[i], (long) x[i], (long) y[i]);
}
/*-------------------------------------------------------------------------*/
/* Do Page Flipping - From ROM Kernal Manual BOB example */
pageflip()
{
scrn->ViewPort.RasInfo->BitMap = bitmap_ptrs[toggle_page];
WaitTOF();
MakeScreen(scrn);
RethinkDisplay();
toggle_page ^=1;
scrn->RastPort.BitMap = bitmap_ptrs[toggle_page];
}
/*-------------------------------------------------------------------------*/
/* New Terrain */
draw_new_row()
{
short i, x;
UWORD *image;
for (i=0, x=0; i<N_HBLK; i++, x+=BLK_W) {
switch ( rowdata[i] ) {
case GROUND: image = ground; break;
case VOLCANO: image = volcano; break;
case PLANT: image = plant; break;
default: image = ground; break;
}
drawblock( image, x, toggle_page);
}
}
/*-------------------------------------------------------------------------*/
/* Paint playfield */
paint_pf()
{
short i, j, x, y;
for (j=0, y=0; j<N_VBLK; j++, y+=BLK_H)
for (i=0, x=0; i<N_HBLK; i++, x+=BLK_W)
drawblock( &ground, x, y);
shadow( 35, 70, 6, "Double-Buffered Infinite BitMap");
shadow( 35, 80, 6, " Scroll Demonstration Program");
shadow( 35, 90, 6, "by Mark Edward Whitehead 1989");
shadow( 50, 130, 7, "Joystick Controls SpaceShip");
shadow( 50, 140, 7, "Spacebar will STOP/START Scroll");
shadow( 50, 150, 7, "T toggles Page Flip display");
shadow( 50, 160, 7, "Q quits Demonstration");
}
/*-------------------------------------------------------------------------*/
/* Draw a block on screen */
drawblock( p, x, y)
UWORD *p;
short x, y;
{
block.LeftEdge = x;
block.TopEdge = y;
block.ImageData = p;
DrawImage( rp, &block, 0L, 0L);
}
/*-------------------------------------------------------------------------*/
/* Set up the sprites. This routine and it's support routines take the */
/* hassle out of using Sprites. What I do is create a buffer which is */
/* partitioned into areas the size of the largest Sprite and has big as */
/* the number of Sprite shapes I'm going to need. Then the data is copied */
/* into this CHIP buffer. Now I can quickly calculate the offset into the */
/* buffer to change my sprite shapes. MEW */
setupsprites()
{
if (!(sprbuffer = AllocMem( (long) 2*SPRSIZE*NSPRITES, MEMF_CHIP) ))
die("No memory for sprite data.");
add_spr( SHIPL, shipl);
add_spr( SHIPR, shipr);
add_spr( ALIEN0, alien);
add_spr( ALIEN1, alien);
add_spr( ALIEN2, alien);
add_spr( ALIEN3, alien);
add_spr( MISSILE, missile);
init_sprite( &shiplspr, SHIPL, 2, sx, sy, 32);
init_sprite( &shiprspr, SHIPR, 3, sx+16, sy, 32);
init_sprite( &alienspr[0], ALIEN0, 6, x[0], y[0], 15);
init_sprite( &alienspr[1], ALIEN1, 7, x[1], y[1], 15);
init_sprite( &alienspr[2], ALIEN2, 4, x[2], y[2], 15);
init_sprite( &alienspr[3], ALIEN3, 5, x[3], y[3], 15);
init_sprite( &mslspr, MISSILE, 1, mx, my, 15);
}
/*-------------------------------------------------------------------------*/
/* Initialize a sprite */
init_sprite( s, shpnum, n, x, y, h)
struct SimpleSprite *s;
short shpnum, n, x, y, h;
{
if ( GetSprite( s, (long) n) < 0 ) die("Sprite not available.");
s->x = x;
s->y = y;
s->height = h;
ChangeSprite( vp, s, sprbuffer + shpnum * SPRSIZE);
}
/*-------------------------------------------------------------------------*/
/* Add a sprite data to the CHIP ram buffer. SPRSIZE is the largest spr */
add_spr( n, src)
UWORD n, *src;
{
short i;
UWORD *buffer;
buffer = sprbuffer + n * SPRSIZE;
for (i=0; i<SPRSIZE; i++) *buffer++ = *src++;
}
/*-------------------------------------------------------------------------*/
/* Get memory for a double buffered bit map */
get_bitmaps()
{
short i, j;
for(j=0; j<2; j++) {
if ((bitmap_ptrs[j] = AllocMem( (long) sizeof(struct BitMap), MEMF_CHIP)) == 0)
die("Can't get bitmap memory");
InitBitMap(bitmap_ptrs[j], DEPTH, WIDTH, RHEIGHT);
for(i=0; i<DEPTH; i++) {
if ((bitmap_ptrs[j]->Planes[i] = (PLANEPTR)
AllocRaster(WIDTH, RHEIGHT)) == 0)
die("Can't get bitmap planes");
BltClear(bitmap_ptrs[j]->Planes[i],(long) (WIDTH/8)*RHEIGHT, 1L);
}
}
}
/*-------------------------------------------------------------------------*/
/* Free memory for a double buffered bit map */
free_bitmaps()
{
short i, j;
for (j=0; j<2; j++) {
if (bitmap_ptrs[j]) {
for (i=0; i<DEPTH; i++) {
if (bitmap_ptrs[j]->Planes[i] != 0)
FreeRaster(bitmap_ptrs[j]->Planes[i], WIDTH, RHEIGHT);
}
FreeMem(bitmap_ptrs[j], (long) sizeof(struct BitMap));
}
}
}
/*-------------------------------------------------------------------------*/
/* Print drop-shadow text to rastport */
shadow( x, y, color, txt)
short x, y, color;
char *txt;
{
SetDrMd( rp, (long) JAM1);
SetAPen( rp, (long) 0L);
Move( rp, (long) x-1, (long) y+1);
Text( rp, (long) txt, (long) strlen(txt) );
SetAPen( rp, (long) color);
Move( rp, (long) x, (long) y);
Text( rp, (long) txt, (long) strlen(txt) );
}
/*-------------------------------------------------------------------------*/
/* Jam those colors into the display */
jamit( x, y, color, txt)
short x, y, color;
char *txt;
{
SetDrMd( rp, (long) JAM2);
SetBPen( rp, (long) 0);
SetAPen( rp, (long) color);
Move( rp, (long) x, (long) y);
Text( rp, (long) txt, (long) strlen(txt) );
}
/*-------------------------------------------------------------------------*/
/* Read joystick hardware directly and return delta x, delta y and fire */
/* button discrete. Note that this routine bypasses normal i/o functions */
/* so that any screen blanker program, for example, won't hear about it... */
joystick( dx, dy, fire)
USHORT *dx, *dy, *fire;
{
USHORT *joy = (USHORT *) 0xdff00c;
USHORT *button = (USHORT *) 0xbfe0fe;
USHORT sample;
sample = *joy & 771; /* Mask off Non-Joystick bits */
switch (sample) {
case 0: *dx = 0; *dy = 0; break; /* Center */
case 1: ++(*dy); break; /* Down */
case 2: ++(*dy); ++(*dx); break; /* Down, Right */
case 3: ++(*dx); break; /* Right */
case 256: --(*dy); break; /* Up */
case 259: --(*dy); ++(*dx); break; /* Up, Right */
case 512: --(*dy); --(*dx); break; /* Up, Left */
case 768: --(*dx); break; /* Left */
case 769: ++(*dy); --(*dx); break; /* Down, Left */
default: *dx = 0; *dy = 0;
}
if ( !(*button & 0x0080) ) *fire = TRUE; else *fire = FALSE;
}
/*-------------------------------------------------------------------------*/
/* Open up system libraries and stuff */
openstuff()
{
if (!(IntuitionBase = OpenLibrary ("intuition.library", REV)))
die ("Intuition doesn't 'open up' to me.");
if (!(GfxBase = OpenLibrary ("graphics.library", REV)))
die ("Art shop closed.");
get_bitmaps(); /* Allocate custom bitmaps for dbuf */
scrndef.CustomBitMap = bitmap_ptrs[0];
scrn->RastPort.Flags = DBUFFER;
if (!(scrn = OpenScreen (&scrndef)))
die ("Screen painted shut.");
windef.Screen = scrn;
if (!(win = OpenWindow( &windef)))
die ("Window stuck tight.");
vp = &(scrn -> ViewPort);
rp = &(scrn -> RastPort);
LoadRGB4( vp, colortable, 32L);
/* Make the screen using pointer to bitmap 0 */
scrn->ViewPort.RasInfo->BitMap = bitmap_ptrs[0];
scrn->ViewPort.RasInfo->RyOffset = BLK_H;
MakeScreen(scrn);
RethinkDisplay();
}
/*-------------------------------------------------------------------------*/
/* Close what we opened, deallocate what we allocated */
closestuff()
{
if (sprbuffer)
FreeMem( sprbuffer, (long) 2*SPRSIZE*NSPRITES);
if (shiplspr.num)
FreeSprite( (long) shiplspr.num );
if (shiprspr.num)
FreeSprite( (long) shiprspr.num );
if (alienspr[0].num)
FreeSprite( (long) alienspr[0].num );
if (alienspr[1].num)
FreeSprite( (long) alienspr[1].num );
if (alienspr[2].num)
FreeSprite( (long) alienspr[2].num );
if (alienspr[3].num)
FreeSprite( (long) alienspr[3].num );
if (mslspr.num)
FreeSprite( (long) mslspr.num );
if (win)
CloseWindow(win);
if (scrn)
CloseScreen(scrn);
free_bitmaps(); /* This must be done AFTER screen closed */
if (GfxBase)
CloseLibrary (GfxBase);
if (IntuitionBase)
CloseLibrary (IntuitionBase);
}
/*-------------------------------------------------------------------------*/
/* Post a complaint on the way out */
die(str)
char *str;
{
puts(str);
closestuff();
exit (-1);
}